package com.ruoyi.system.utils;

/**
 * @author : 王孟轩
 * @date : 2025/3/1 9:59
 * @description : 资金账户 Excel 解析工具类
 */
import com.ruoyi.system.domain.CapitalAccount; // 导入资金账户实体类
import com.ruoyi.system.mapper.CapitalAccountMapper;
import org.apache.poi.ss.usermodel.*; // 导入 Apache POI 相关类用于处理 Excel 文件
import org.apache.poi.xssf.usermodel.XSSFWorkbook; // 导入 XSSFWorkbook 类用于处理 .xlsx 文件
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile; // 导入 MultipartFile 类用于处理上传文件

import java.io.IOException; // 导入 IOException 类用于处理 IO 异常
import java.io.InputStream; // 导入 InputStream 类用于读取文件流

import java.util.ArrayList; // 导入 ArrayList 类用于创建列表
import java.util.Date; // 导入 Date 类用于处理日期
import java.util.HashMap;
import java.util.List; // 导入 List 接口用于定义列表类型
import java.util.concurrent.ConcurrentHashMap;

@Component
public class CapitalAccountExcelParser {

    @Autowired
    CapitalAccountMapper capitalAccountMapper;

    /**
     * 解析 Excel 文件并返回结果
     *
     * @param file 上传的 Excel 文件（.xlsx）
     * @return 包含数据和错误的解析结果
     */
    public  ExcelParseResult<CapitalAccount> parse(MultipartFile file) throws IOException {
        Long number = capitalAccountMapper.number(1);
        Long number3 = capitalAccountMapper.number(2);
        int number1 = 0;
        int number2 = 0;
        if (number!=0){
            number1 = Math.toIntExact(number);
        }
        if (number3!=0){
            number2 = Math.toIntExact(number3);
        }
        List<CapitalAccount> data = new ArrayList<>(); // 创建一个列表用于存储解析后的数据
        List<ExcelParseError> errors = new ArrayList<>(); // 创建一个列表用于存储解析过程中遇到的错误

        try (InputStream is = file.getInputStream(); // 获取上传文件的输入流
             Workbook workbook = new XSSFWorkbook(is)) { // 使用 XSSFWorkbook 打开 Excel 文件

            Sheet sheet = workbook.getSheetAt(0); // 获取第一个工作表
            for (Row row : sheet) { // 遍历工作表中的每一行
                // 跳过标题行（根据需求调整）
                if (row.getRowNum() == 0) continue; // 如果是第一行（标题行），则跳过

                try {
                    HashMap<String, Object> map = mapRowToCapitalAccount(row, row.getRowNum(), number1, number2);// 将当前行映射为 CapitalAccount 对象
                    if (map.get("account") != null) {


                        data.add((CapitalAccount) map.get("account")); // 如果映射成功，将对象添加到数据列表中
                        number2 = (int) map.get("number2");
                        number1 = (int) map.get("number1");
                    }
                } catch (Exception e) {
                    errors.add(new ExcelParseError(row.getRowNum(), e.getMessage())); // 如果映射失败，记录错误信息
                }
            }
        }

        return new ExcelParseResult<>(data, errors); // 返回包含数据和错误的解析结果
    }

    /**
     * 将 Excel 行映射为 CapitalAccount 对象
     *
     * @param row   当前行
     * @param rowNum 行号
     * @return 映射后的 CapitalAccount 对象
     */
    private static HashMap<String,Object> mapRowToCapitalAccount(Row row, int rowNum,int number1,int number2) throws Exception {
        CapitalAccount account = new CapitalAccount(); // 创建一个新的 CapitalAccount 对象
        HashMap<String, Object> map = new HashMap<>();
        // 0. 账户类别（第一列）
        Cell accountSortCell = row.getCell(0); // 获取当前行的第一列单元格
        if (accountSortCell != null && !isCellEmpty(accountSortCell)) {
            account.setAccountSort((int) getNumericValue(accountSortCell)); // 设置账户类别
        } else {
            throw new Exception("第" + rowNum + "行：账户类别不能为空");
        }

        // 1. 账户名称（第二列）
        Cell accountTitleCell = row.getCell(1); // 获取当前行的第二列单元格
        if (accountTitleCell != null && !isCellEmpty(accountTitleCell)) {
            account.setAccountTitle(getStringValue(accountTitleCell)); // 设置账户名称
        } else {
            throw new Exception("第" + rowNum + "行：账户名称不能为空");
        }
        if (account.getAccountSort() == 1) {
            // 2. 银行编码（第三列）
            Cell bankCodeCell = row.getCell(2); // 获取当前行的第三列单元格
            if (bankCodeCell != null && !isCellEmpty(bankCodeCell)) {
                account.setBankId((int) getNumericValue(bankCodeCell)); // 设置银行编码
            } else {
                throw new Exception("第" + rowNum + "行：银行编码为空或格式错误");
            }

            // 3. 银行账号（第四列）
            Cell cardNumberCell = row.getCell(3); // 获取当前行的第四列单元格
            if (cardNumberCell != null && !isCellEmpty(cardNumberCell)) {
                account.setCardNumber(getLongValue(cardNumberCell)); // 设置银行卡号
            } else {
                throw new Exception("第" + rowNum + "行：银行账号不能为空");
            }
            // 5. 到期日期（第七列）
            Cell cell = row.getCell(5);// 获取当前行的第六列单元格
            if (cell != null && !isCellEmpty(cell)) {
                account.setMaturityDate(cell.getDateCellValue()); // 设置会计科目
            } else {
                throw new Exception("第" + rowNum + "行：过期日期不能为空");
            }
        }
        // 4. 币别（第五列）
        Cell currencyIdCell = row.getCell(4); // 获取当前行的第五列单元格
        if (currencyIdCell != null && !isCellEmpty(currencyIdCell)) {
            account.setCurrencyId((int) getNumericValue(currencyIdCell)); // 设置币别
        } else {
            throw new Exception("第" + rowNum + "行：币别不能为空");
        }

        // 5. 会计科目（第六列）
        Cell subjectIdCell = row.getCell(5); // 获取当前行的第六列单元格
        if (subjectIdCell != null && !isCellEmpty(subjectIdCell)) {
            account.setSubjectId((int) getNumericValue(subjectIdCell)); // 设置会计科目
        } else {
            throw new Exception("第" + rowNum + "行：会计科目不能为空");
        }


        account.setCodingState(1);
        account.setCreatedDate(new Date());
        account.setInterconnect("未连接");

        if (account.getAccountSort() == 1) {
            account.setAccountCoding(String.format("CA%03d", number1));
            number1= number1 + 1;
        } else {
            account.setAccountCoding(String.format("CA%03d", number2));
            number2= number2 + 1;
        }
        map.put("number1",number1);
        map.put("number2",number2);
        map.put("account",account);
        return map; // 返回映射后的 CapitalAccount 对象
    }

    // 辅助方法：安全获取单元格的数值（支持多种单元格类型）
    private static double getNumericValue(Cell cell) {
        switch (cell.getCellType()) {
            case NUMERIC:
                return cell.getNumericCellValue();
            case STRING:
                try {
                    return Double.parseDouble(cell.getStringCellValue().trim());
                } catch (NumberFormatException e) {
                    throw new RuntimeException("无法将字符串转换为数字：" + cell.getStringCellValue());
                }
            default:
                throw new RuntimeException("未知单元格类型：" + cell.getCellType());
        }
    }

    // 辅助方法：安全获取单元格的长整型数值
    private static long getLongValue(Cell cell) {
        return (long) getNumericValue(cell);
    }

    // 辅助方法：安全获取单元格的字符串值
    private static String getStringValue(Cell cell) {
        switch (cell.getCellType()) {
            case STRING:
                return cell.getStringCellValue().trim();
            case NUMERIC:
                return String.valueOf(cell.getNumericCellValue());
            default:
                throw new RuntimeException("未知单元格类型：" + cell.getCellType());
        }
    }

    // 辅助方法：检查单元格是否为空
    private static boolean isCellEmpty(Cell cell) {
        return cell == null || cell.getCellType() == CellType.BLANK ||
                (cell.getCellType() == CellType.STRING && cell.getStringCellValue().trim().isEmpty());
    }
}
